#include "app.h"

// Checa se os dados lidos da FLASH estão corretos
int check_Values(void) {
	tParServo* parServo;
	int x; for(x=0;x<SERVO_N_MODULE;x++) {
		parServo = (tParServo*)control.servo[x].par;

		if ( (parServo->offset < minOFFSET_US) || (parServo->offset > maxOFFSET_US) ) return errSERVO_PAR_OFFSET;
		if ( (parServo->init < minSERVO_US) || (parServo->init > maxSERVO_US) ) return errSERVO_PAR_INIT;
		if ( (parServo->min < minSERVO_US) || (parServo->min > maxSERVO_US) ) return errSERVO_PAR_MIM;
		if ( (parServo->max < minSERVO_US) || (parServo->max > maxSERVO_US) ) return errSERVO_PAR_MAX;
		if ( (parServo->timeProgress < minTIME_PROGRESS) || (parServo->timeProgress > maxTIME_PROGRESS) ) return errSERVO_PAR_TIME_PROGRESS;
		if ( (parServo->timeActiveOff < minTIME_OFF) || (parServo->timeActiveOff > maxTIME_OFF) ) return errSERVO_PAR_TIME_OFF;
	}

	return pdOK;
}

// ###########################################################################################
// VALORES PADRÕES
void par_ValuesDefaults(void) {
	#if (LOG_APP == pdON)
	plog("ALL VALUE DEFAULT"CMD_TERMINATOR);
	#endif

	tParServo* parServo;
	int x; for(x=0;x<SERVO_N_MODULE;x++) {
		parServo = (tParServo*)control.servo[x].par;
		parServo->offset = 0;
		parServo->init = 1500;
		parServo->min = minSERVO_US;
		parServo->max = maxSERVO_US;
		parServo->timeProgress = 0;
		parServo->timeActiveOff = 0;
	}
}


// ###########################################################################################
// GERENCIAMENTO DE VALORES ARMAZENADOS NO FINAL DA FLASH DE PROGRAMA

// Lê valores de configurações na flash, caso não conter valores válidos, colocar valores padrões
// Também lê os logs de erros
void flash_Load(void) {
	int x, y;
	tDataFlash* p = (tDataFlash*) (0xf000);
	tLogFlash* pLog = (tLogFlash*) (0xe000);
	// calcular o CRC da flash
	u16 crc = crc16_MODBUS(p, (sizeof(tDataFlash))-2);

	// carregar os logs de erro
	tDataLog* pl = pLog->err;
	for(x=0;x<nLOG;x++) {
		// se o os valores da flash forem inválidos  (ID) ou o código for 0xFF, não há erro gravados
		if (pl->code == 0xFF) {
			control.err[x].countTick = 0;
			control.err[x].code = 0;
		} else {
			control.err[x].countTick = pl->countTick;
			control.err[x].code = pl->code;
		}
		pl++;
	}

	// Se o ID está correto e CRC errado, é porque houve algum erro de hardware ou durante a gravação
	if ( (crc != p->crc) && (p->id == idFLASH) ) {
		showVicError(errCRC_FLASH); // trava no loop sinalizando o erro
	// Se o CRC e o ID estão corretos vamos carregar todos os valores
	} if ( (crc == p->crc) && (p->id == idFLASH) )  {
		#if (LOG_APP == pdON)
		plog("LOAD FLASH id:0x%x crc:%d"CMD_TERMINATOR, p->id, p->crc);
		#endif

		tParServo* pserv = p->parServo;
		s32* par;
		for(x=0;x<SERVO_N_MODULE;x++) {
			par = &pserv->offset;
			for(y=0;y<nPAR_SERVO;y++) control.servo[x].par[y] = *par++;
			pserv++;
		}
	} else {
		// Todos os parametros assumirem valores padrões
		par_ValuesDefaults();
		flash_Save();
	}
}

// Salvas dados de calibração no final da flash
#include "vic.h"
int flash_Save(void) {
	int x,y;
	u8 dataBuf[lenFLASH];
	tDataFlash* p = (tDataFlash*) dataBuf;

	irq_Disable(); 		// Desabilitar interrupções

	for(x=0;x<lenFLASH;x++) dataBuf[x] = 0xFF;

	// Antes de gravar na flash é preciso preparar o setor para gravação
	if (iap_ClearSectors(15,15) != pdPASS) return pdFAIL;

	p->id = idFLASH;
	//p->par.offset1 = pPar->offset1;

	tParServo* pserv = p->parServo;
	s32* par;
	for(x=0;x<SERVO_N_MODULE;x++) {
		par = &pserv->offset;
		for(y=0;y<nPAR_SERVO;y++) *par++=control.servo[x].par[y];
		pserv++;
	}

	p->crc = crc16_MODBUS(dataBuf, (sizeof(tDataFlash))-2);

	// gravar na FLASH. Somente aceita buffers de tamanhos de 256, 512, 1024 ou 4096 KB dependendo do setor
	if (iap_WriteSectors (0xf000, (u8*)dataBuf, lenFLASH) != pdPASS) return pdFAIL;

	irq_Enable(); 	// Habilitar interrupções
	control.ticks = 0; // Inicializa o ticks para que o relé seja atracado navamente caso se demorou muito para gravar na flash

	#if (LOG_APP == pdON)
	plog("SAVE FLASH crc = %d"CMD_TERMINATOR, p->crc);
	#endif

	return pdPASS;
}

static int flash_SaveLog(void) {
	int x;
	u8 dataBuf[lenFLASH_LOG];
	tLogFlash* p = (tLogFlash*) dataBuf;

	for(x=0;x<lenFLASH_LOG;x++) dataBuf[x] = 0xFF;

	// Antes de gravar na flash é preciso preparar o setor para gravação
	if (iap_ClearSectors(14,14) != pdPASS) return pdFAIL;

	tDataLog* pl = p->err;
	for(x=0;x<nLOG;x++) {
		pl->countTick = control.err[x].countTick;
		pl->code = control.err[x].code;
		pl++;
	}

	p->crc = crc16_MODBUS(dataBuf, (sizeof(tLogFlash))-2);

	// gravar na FLASH. Somente aceita buffers de tamanhos de 256, 512, 1024 ou 4096 KB dependendo do setor
	if (iap_WriteSectors (0xe000, (u8*)dataBuf, lenFLASH_LOG) != pdPASS) return pdFAIL;

	return pdPASS;
}

// limpa os logs de erro
int flash_ClearLogError(void) {
	uint x; for(x=0; x<nLOG;x++) {
		control.err[x].countTick = 0;
		control.err[x].code = 0;
	}

	return flash_SaveLog();
}

// salva o erro no primeiro slot disponivel. Salvar na posição da FLASH diferente dos parametros
int flash_SaveLogError(u32 countTicks, u8 n) {
	int res = pdFALSE;

	// encontrar até um slot vazio, uma vez encontrado salva na flash e cai fora
	uint x; for(x=0; x<nLOG;x++)
		if (control.err[x].code == 0) {
			control.err[x].countTick = countTicks;
			control.err[x].code = n;
			res = flash_SaveLog();
			break;
		}

	return res;
}
